//
// Created by heqian on 17-8-2.
//

#include "EditImage.h"

namespace img {
    Prt<EditImage> EditImage::mInterface;

    EditImage::EditImage() {
        mGrayColorR = (uint32_t *) malloc((0x100) * 3 * sizeof(uint32_t));
        mGrayColorG = mGrayColorR + 0x100;
        mGrayColorB = mGrayColorG + 0x100;
        for (int i = 0; i < 0x100; i++) {
            *(mGrayColorR + i) = i * 4898;
            *(mGrayColorG + i) = i * 9618;
            *(mGrayColorB + i) = i * 1868;
        }

        mDrawColor = (uint16_t *) malloc(0x10000 * sizeof(uint16_t));
        uint16_t *temp;
        for (int y = 0; y < 0x100; y++) {
            temp = mDrawColor + (y << 8);
            for (int x = 0; x < 0x100; x++) {
                *(temp + x) = y * x;
            }
        }
    }

    EditImage::~EditImage() {
        free(mGrayColorR);
        free(mDrawColor);
    }


    Prt<Image> EditImage::threshold(Prt<Image> &src, uint8_t value) {
        int width = src->getWidth();
        int height = src->getHeight();

        Prt<Image> ret = new Image(width, height, IMAGE_FORMAT_A_8);
        uint8_t *retData = (uint8_t *) ret->getData();
        uint8_t *endData = retData + width * height;
        uint8_t temp;
        if (IMAGE_FORMAT_RGBA_8888 == src->getFormat()) {
            uint32_t *srcData32 = (uint32_t *) src->getData();
            for (; retData < endData; ++retData, ++srcData32) {
                *retData = (value - ((*(mGrayColorR + R(*srcData32)) +
                                      *(mGrayColorG + G(*srcData32)) +
                                      *(mGrayColorB + B(*srcData32)) >> 14) & 0xFF)) >> 7;
            }
        } else if (IMAGE_FORMAT_A_8 == src->getFormat()) {
            uint8_t *srcData8 = (uint8_t *) src->getData();
            for (; retData < endData; ++retData, ++srcData8) {
                *retData = (value - *srcData8) >> 7;
            }
        }

        return ret;
    }

    Prt<Image> EditImage::gray(Prt<Image> &src) {
        int width = src->getWidth();
        int height = src->getHeight();

        Prt<Image> ret = new Image(width, height, IMAGE_FORMAT_A_8);
        uint8_t *retData = (uint8_t *) ret->getData();
        uint8_t *endData = retData + width * height;

        if (IMAGE_FORMAT_RGBA_8888 == src->getFormat()) {
            uint32_t *srcData = (uint32_t *) src->getData();
            for (; retData < endData; ++retData, ++srcData) {
                *retData = (*(mGrayColorR + R(*srcData)) +
                            *(mGrayColorG + G(*srcData)) +
                            *(mGrayColorB + B(*srcData))) >> 14;
            }
        }
        return ret;
    }

    Prt<Image> EditImage::channel(Prt<Image> &src, ImageChannel channe) {
        int width = src->getWidth();
        int height = src->getHeight();

        Prt<Image> ret = new Image(width, height, IMAGE_FORMAT_A_8);
        uint8_t *retData = (uint8_t *) ret->getData();
        uint8_t *endData = retData + width * height;

        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888:
                int digit = 8 * (4 - channe);
                uint32_t *srcData = (uint32_t *) src->getData();
                for (; retData < endData; retData++, srcData++) {
                    *retData = *srcData >> digit;
                }
                break;
        }

        return ret;
    }

    Prt<Image> EditImage::toRGBA_8888(Prt<Image> &src) {
        int width = src->getWidth();
        int height = src->getHeight();

        Prt<Image> ret = new Image(width, height, IMAGE_FORMAT_RGBA_8888);
        uint32_t *retData = (uint32_t *) ret->getData();
        uint32_t *endData = retData + width * height;

        switch (src->getFormat()) {
            case IMAGE_FORMAT_A_8:
                uint8_t *srcData = (uint8_t *) src->getData();
                for (; retData < endData; retData++, srcData++) {
                    *retData = 0xFF000000 | (*srcData << 16) | (*srcData << 8) | *srcData;
                }
                break;
        }

        return ret;
    }

    Prt<Image> EditImage::invert(Prt<Image> &src) {
        int width = src->getWidth();
        int height = src->getHeight();
        Prt<Image> ret;

        if (IMAGE_FORMAT_RGBA_8888 == src->getFormat()) {
            ret = new Image(width, height, IMAGE_FORMAT_RGBA_8888);
            uint32_t *retData32 = (uint32_t *) ret->getData();
            uint32_t *endData32 = retData32 + width * height;
            uint32_t *srcData32 = (uint32_t *) src->getData();
            for (; retData32 < endData32; retData32++, srcData32++) {
                *retData32 = (~*srcData32 & 0xFFFFFF) | (*srcData32 & 0xFF000000);
            }
        } else if (IMAGE_FORMAT_A_8 == src->getFormat()) {
            ret = new Image(width, height, IMAGE_FORMAT_A_8);
            uint8_t *retData8 = (uint8_t *) ret->getData();
            uint8_t *endData8 = retData8 + width * height;
            uint8_t *srcData8 = (uint8_t *) src->getData();
            for (; retData8 < endData8; retData8++, srcData8++) {
                *retData8 = ~*srcData8;
            }
        }
        return ret;
    }

    Prt<Image>
    EditImage::channelMerge(Prt<Image> &r8, Prt<Image> &g8, Prt<Image> &b8) {
        int width = r8->getWidth();
        int height = r8->getHeight();
        Prt<Image> ret = new Image(width, height, IMAGE_FORMAT_RGBA_8888);

        if (IMAGE_FORMAT_A_8 == r8->getFormat() &&
            IMAGE_FORMAT_A_8 == g8->getFormat() &&
            IMAGE_FORMAT_A_8 == b8->getFormat() &&
            g8->getWidth() == width &&
            g8->getHeight() == height &&
            b8->getWidth() == width &&
            b8->getHeight() == height) {

            uint32_t *retData = (uint32_t *) ret->getData();
            uint32_t *endData = retData + width * height;

            uint8_t *rData = (uint8_t *) r8->getData();
            uint8_t *gData = (uint8_t *) r8->getData();
            uint8_t *bData = (uint8_t *) b8->getData();

            for (; retData < endData; retData++, rData++, gData++, bData++) {
                *retData = 0xFF000000 | (*bData << 16) | (*gData << 8) | *rData;
            }
        }

        return ret;
    }

    Prt<Image>
    EditImage::channelMerge(Prt<Image> &r8, Prt<Image> &g8, Prt<Image> &b8,
                            Prt<Image> &a8) {
        int width = r8->getWidth();
        int height = r8->getHeight();
        Prt<Image> ret = new Image(width, height, IMAGE_FORMAT_RGBA_8888);


        if (IMAGE_FORMAT_A_8 == r8->getFormat() &&
            IMAGE_FORMAT_A_8 == g8->getFormat() &&
            IMAGE_FORMAT_A_8 == b8->getFormat() &&
            IMAGE_FORMAT_A_8 == a8->getFormat() &&
            g8->getWidth() == width &&
            g8->getHeight() == height &&
            a8->getWidth() == width &&
            a8->getHeight() == height &&
            b8->getWidth() == width &&
            b8->getHeight() == height) {

            uint32_t *retData = (uint32_t *) ret->getData();
            uint32_t *endData = retData + width * height;

            uint8_t *rData = (uint8_t *) r8->getData();
            uint8_t *gData = (uint8_t *) r8->getData();
            uint8_t *bData = (uint8_t *) b8->getData();
            uint8_t *aData = (uint8_t *) a8->getData();

            for (; retData < endData; retData++, rData++, gData++, bData++, aData++) {
                *retData = ((uint32_t) *rData) | (*aData << 24) | (*bData << 16) | (*gData << 8);
            }
        }

        return ret;
    }


    Prt<Image> EditImage::clip(Prt<Image> &src, Rect &rect) {
        return EditImage::clip(src, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
    }

    Prt<Image> EditImage::clip(Prt<Image> &src, int x, int y, int width, int height) {
        DrawRect rect(src->getWidth(), src->getHeight(), x, y, width, height);

        x = rect.getSX();
        y = rect.getSY();
        int rx = rect.getDX();
        int ry = rect.getDY();
        int dWidth = rect.getDWidth();
        int dHeight = rect.getDHeight() + y;
        int sWidht = src->getWidth();

        Prt<Image> ret;
        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {

                ret = new Image(width, height, IMAGE_FORMAT_RGBA_8888);
                uint32_t *retData = (uint32_t *) ret->getData();
                uint32_t *srcData = (uint32_t *) src->getData();
                uint32_t *retPixel, *srcPixel, *end;

                for (; y < dHeight; y++, ry++) {
                    srcPixel = end = srcData + sWidht * y + x;
                    end += dWidth;
                    retPixel = retData + width * ry + rx;
                    for (; srcPixel < end; srcPixel++, retPixel++) {
                        *retPixel = *srcPixel;
                    }
                }
                break;
            }
            case IMAGE_FORMAT_A_8: {
                ret = new Image(width, height, IMAGE_FORMAT_A_8);
                uint8_t *retData = (uint8_t *) ret->getData();
                uint8_t *srcData = (uint8_t *) src->getData();
                uint8_t *retPixel, *srcPixel, *end;

                for (; y < dHeight; y++, ry++) {
                    srcPixel = end = srcData + sWidht * y + x;
                    end += dWidth;
                    retPixel = retData + width * ry + rx;
                    for (; srcPixel < end; srcPixel++, retPixel++) {
                        *retPixel = *srcPixel;
                    }
                }
                break;
            }
        }
        return ret;
    }


    bool EditImage::fillColor(Prt<Image> &src, int color) {
        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {
                uint32_t *retData = (uint32_t *) src->getData();
                uint32_t *endData = retData + src->getWidth() *
                                              src->getHeight();

                for (; retData < endData; retData++) {
                    *retData = color;
                }
                return true;
            }
            case IMAGE_FORMAT_A_8: {
                uint8_t *retData = (uint8_t *) src->getData();
                uint8_t *endData = retData + src->getWidth() *
                                             src->getHeight();
                uint8_t dColor = (R(color) * 4898 +
                                  G(color) * 9618 +
                                  B(color) * 1868) >> 14;
                for (; retData < endData; retData++) {
                    *retData = dColor;
                }
                return true;
            }
        }
        return false;
    }

    bool EditImage::drawColor(Prt<Image> &src, int color) {
        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {
                uint32_t *srcData = (uint32_t *) src->getData();
                uint32_t *endData = srcData + src->getWidth() *
                                              src->getHeight();
                uint8_t r = R(color);
                uint8_t g = G(color);
                uint8_t b = B(color);
                uint8_t a = A(color);

                for (; srcData < endData; srcData++) {

//                    *srcData = ((uint32_t) ((A(*srcData) | a) & 0xFF << 24)) |
//                               AB(B(*srcData), b, a) << 16 |
//                               AB(G(*srcData), g, a) << 8 |
//                               AB(R(*srcData), r, a);
                }
                return true;
            }
            case IMAGE_FORMAT_A_8: {
                uint8_t *srcData = (uint8_t *) src->getData();
                uint8_t *endData = srcData + src->getWidth() *
                                             src->getHeight();
                uint8_t a = A(color);
                uint8_t dColor = (R(color) * 4898 +
                                  G(color) * 9618 +
                                  B(color) * 1868) >> 14;

                for (; srcData < endData; srcData++) {
//                    *srcData = AB(*srcData, dColor, a);
                }
                return true;
            }
        }
        return false;
    }

    bool EditImage::fillColor(Prt<Image> &src, int color, Rect &rect) {
        DrawRect dRect(src->getWidth(),
                       src->getHeight(), rect.getX(), rect.getY(),
                       rect.getWidth(),
                       rect.getHeight());
        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {
                uint32_t *srcPixel, *endX, *srcData = (uint32_t *) src->getData();
                uint32_t y = dRect.getSY();
                uint32_t x = dRect.getSX();
                uint32_t height = src->getWidth();
                uint32_t dWidth = dRect.getDWidth();
                uint32_t endY = dRect.getDHeight() + y;

                for (; y < endY; y++) {
                    srcPixel = endX = srcData + height * y + x;
                    endX += dWidth;

                    for (; srcPixel < endX; srcPixel++) {
                        *srcPixel = color;
                    }
                }
                return true;
            }
            case IMAGE_FORMAT_A_8: {
                uint8_t *srcPixel, *endX, *srcData = (uint8_t *) src->getData();
                uint8_t y = dRect.getSY();
                uint8_t x = dRect.getSX();
                uint8_t height = src->getWidth();
                uint8_t dWidth = dRect.getDWidth();
                uint8_t endY = dRect.getDHeight() + y;

                for (; y < endY; y++) {
                    srcPixel = endX = srcData + height * y + x;
                    endX += dWidth;

                    for (; srcPixel < endX; srcPixel++) {
                        *srcPixel = color;
                    }
                }
                return true;
            }
        }
        return false;
    }

    bool EditImage::drawColor(Prt<Image> &src, int color, Rect &rect) {
        DrawRect dRect(src->getWidth(),
                       src->getHeight(), rect.getX(), rect.getY(),
                       rect.getWidth(),
                       rect.getHeight());

        int y = dRect.getSY();
        int x = dRect.getSX();
        int height = src->getWidth();
        int dWidth = dRect.getDWidth();
        int endY = dRect.getDHeight() + y;

        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {
                uint32_t *srcPixel, *endX, *srcData = (uint32_t *) src->getData();
                uint8_t r = R(color);
                uint8_t g = G(color);
                uint8_t b = B(color);
                uint8_t a = A(color);

                for (; y < endY; y++) {
                    srcPixel = endX = srcData + height * y + x;
                    endX += dWidth;

                    for (; srcPixel < endX; srcPixel++) {
//                        *srcPixel = ((uint32_t) ((A(*srcPixel) | a) & 0xFF << 24)) |
//                                    AB(B(*srcPixel), b, a) << 16 |
//                                    AB(G(*srcPixel), g, a) << 8 |
//                                    AB(R(*srcPixel), r, a);
                    }
                }
                return true;
            }
            case IMAGE_FORMAT_A_8: {
                uint8_t *srcPixel, *endX, *srcData = (uint8_t *) src->getData();
                uint8_t a = A(color);
                uint8_t dColor = (R(color) * 4898 +
                                  G(color) * 9618 +
                                  B(color) * 1868) >> 14;

                for (; y < endY; y++) {
                    srcPixel = endX = srcData + height * y + x;
                    endX += dWidth;

                    for (; srcPixel < endX; srcPixel++) {
//                        *srcPixel = AB(*srcPixel, dColor, a);
                    }
                }
                return true;
            }
        }
        return false;
    }

    bool EditImage::fillImage(Prt<Image> &src, Prt<Image> &img, int x, int y) {
        DrawRect dRect(src->getWidth(),
                       src->getHeight(), x, y,
                       img->getWidth(),
                       img->getHeight());

        x = dRect.getSX();
        y = dRect.getSY();
        int width = src->getWidth();
        int dWidth = dRect.getDWidth();
        int endY = dRect.getDHeight() + y;

        int iWidth = img->getWidth();
        int ix = dRect.getDX();
        int iy = dRect.getDY();

        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {
                uint32_t *srcData = (uint32_t *) src->getData();
                uint32_t *imgData = (uint32_t *) img->getData();
                uint32_t *srcPixel, *endX, *imgPixel;

                for (; y < endY; ++y, ++iy) {
                    srcPixel = endX = srcData + width * y + x;
                    endX += dWidth;

                    imgPixel = imgData + iWidth * iy + ix;
                    for (; srcPixel < endX; ++srcPixel, ++imgPixel) {
                        *srcPixel = *imgPixel;
                    }
                }
                return true;
            }
            case IMAGE_FORMAT_A_8: {
                uint8_t *srcData = (uint8_t *) src->getData();
                uint8_t *imgData = (uint8_t *) img->getData();
                uint8_t *srcPixel, *endX, *imgPixel;

                for (; y < endY; y++, iy++) {
                    srcPixel = endX = srcData + width * y + x;
                    endX += dWidth;

                    imgPixel = imgData + iWidth * iy + ix;
                    for (; srcPixel < endX; srcPixel++, imgPixel++) {
                        *srcPixel = *imgPixel;
                    }
                }
                return true;
            }
        }
        return false;
    }

    bool EditImage::drawImage(Prt<Image> &src, Prt<Image> &img, int x, int y) {
        DrawRect dRect(src->getWidth(),
                       src->getHeight(), x, y,
                       img->getWidth(),
                       img->getHeight());

        x = dRect.getSX();
        y = dRect.getSY();
        int width = src->getWidth();
        int dWidth = dRect.getDWidth();
        int endY = dRect.getDHeight() + y;

        int iWidth = img->getWidth();
        int ix = dRect.getDX();
        int iy = dRect.getDY();

        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {
                uint32_t *srcData = (uint32_t *) src->getData();
                uint32_t *imgData = (uint32_t *) img->getData();

                uint32_t *srcPixel, *endX, *imgPixel;
                uint8_t a;
                for (; y < endY; y++, iy++) {
                    srcPixel = endX = srcData + width * y + x;
                    endX += dWidth;

                    imgPixel = imgData + iWidth * iy + ix;
                    for (; srcPixel < endX; srcPixel++, imgPixel++) {
                        a = A(*imgPixel);
                        *srcPixel = ((uint32_t) ((A(*imgPixel) | a) & 0xFF << 24)) |
                                    AB(B(*imgPixel), B(*srcPixel), a) << 16 |
                                    AB(G(*imgPixel), G(*srcPixel), a) << 8 |
                                    AB(R(*imgPixel), R(*srcPixel), a);
                    }
                }
                return true;
            }
            case IMAGE_FORMAT_A_8: {
                uint8_t *srcData = (uint8_t *) src->getData();
                uint8_t *imgData = (uint8_t *) img->getData();

                uint8_t *srcPixel, *endX, *imgPixel;
                for (; y < endY; y++, iy++) {
                    srcPixel = endX = srcData + width * y + x;
                    endX += dWidth;

                    imgPixel = imgData + iWidth * iy + ix;
                    for (; srcPixel < endX; srcPixel++, imgPixel++) {
                        *srcPixel = *imgPixel;
                    }
                }
                return true;
            }
        }
        return false;
    }

    Prt<EditImage> &EditImage::get() {
        if (mInterface.isNull())
            mInterface = new EditImage();
        return mInterface;
    }

    void EditImage::setInterface(const Prt<EditImage> &mInterface) {
        EditImage::mInterface = mInterface;
    }

    Prt<Image> EditImage::mirror(Prt<Image> &src, bool horizontal) {
        int width = src->getWidth();
        int height = src->getHeight();

        Prt<Image> ret;
        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {
                ret = new Image(width, height, IMAGE_FORMAT_RGBA_8888);
                uint32_t *retData, *temp, *srcData = (uint32_t *) src->getData();
                uint32_t *endY = srcData + width * (height - 1);
                if (horizontal) {
                    retData = (uint32_t *) ret->getData();
                    while (srcData < endY) {
                        for (temp = retData + width; temp >= retData; temp--, srcData++) {
                            *temp = *srcData;
                        }
                        retData += width;
                        srcData--;
                    }
                } else {
                    retData = (uint32_t *) ret->getData() + width * (height - 1);
                    for (; srcData < endY; srcData += width, retData -= width) {
                        memcpy(retData, srcData, width * sizeof(uint32_t));
                    }
                }
                break;
            }
            case IMAGE_FORMAT_A_8: {
                ret = new Image(src->getWidth(), src->getHeight(), IMAGE_FORMAT_A_8);
                uint8_t *retData, *temp, *srcData = (uint8_t *) src->getData();
                uint8_t *endY = srcData + width * (height - 1);
                if (horizontal) {
                    retData = (uint8_t *) ret->getData();
                    while (srcData < endY) {
                        for (temp = retData + width; temp >= retData; temp--, srcData++) {
                            *temp = *srcData;
                        }
                        retData += width;
                        srcData--;
                    }
                } else {
                    retData = (uint8_t *) ret->getData() + width * (height - 1);
                    for (; srcData < endY; srcData += width, retData -= width) {
                        memcpy(retData, srcData, width * sizeof(uint8_t));
                    }
                }
                break;
            }
        }
        return ret;
    }

    Prt<Image> EditImage::angleRotation(Prt<Image> &src, RotationAngle angle) {
        int width = src->getWidth();
        int height = src->getHeight();
        int rWidth = Angle_180 == angle ? width : height;
        int rHeight = Angle_180 == angle ? height : width;

        Prt<Image> ret;
        switch (src->getFormat()) {
            case IMAGE_FORMAT_RGBA_8888: {
                ret = new Image(rWidth, rHeight, IMAGE_FORMAT_RGBA_8888);
                uint32_t *retData, *endY, *srcData = (uint32_t *) src->getData();

                if (Angle_180 == angle) {
                    retData = (uint32_t *) ret->getData() + width * (height - 1);
                    endY = srcData + width * (height - 1);
                    for (; srcData < endY; srcData++, retData--) {
                        *retData = *srcData;
                    }
                } else if (Angle_90 == angle) {
                    retData = (uint32_t *) ret->getData();
                    for (int x = rWidth - 1; x >= 0; x--) {
                        for (int y = 0; y < rHeight; y++) {
                            *(retData + y * rWidth + x) = *srcData;
                            srcData++;
                        }
                    }
                } else {
                    retData = (uint32_t *) ret->getData();
                    for (int x = 0; x < rWidth; x++) {
                        for (int y = rHeight - 1; y >= 0; y--) {
                            *(retData + y * rWidth + x) = *srcData;
                            srcData++;
                        }
                    }
                }
                break;
            }
            case IMAGE_FORMAT_A_8: {
                ret = new Image(rWidth, rHeight, IMAGE_FORMAT_RGBA_8888);
                uint8_t *retData, *endY, *srcData = (uint8_t *) src->getData();

                if (Angle_180 == angle) {
                    retData = (uint8_t *) ret->getData() + width * (height - 1);
                    endY = srcData + width * (height - 1);
                    for (; srcData < endY; srcData++, retData--) {
                        *retData = *srcData;
                    }
                } else if (Angle_90 == angle) {
                    retData = (uint8_t *) ret->getData();
                    for (int x = rWidth - 1; x >= 0; x--) {
                        for (int y = 0; y < rHeight; y++) {
                            *(retData + y * rWidth + x) = *srcData;
                            srcData++;
                        }
                    }
                } else {
                    retData = (uint8_t *) ret->getData();
                    for (int x = 0; x < rWidth; x++) {
                        for (int y = rHeight - 1; y >= 0; y--) {
                            *(retData + y * rWidth + x) = *srcData;
                            srcData++;
                        }
                    }
                }
                break;
            }
        }
        return ret;
    }

    Prt<Image> EditImage::zoomImage_Near(Prt<Image> &src, int width, int height) {
        int sWidth = src->getWidth();
        int sHeight = src->getHeight();
        float scaleX = (float) sWidth / width;
        float scaleY = (float) sHeight / height;

        int *tabX = (int *) malloc(width * sizeof(int));
        int *end = tabX + width;
        for (int x = 0; x < width; ++x)
            *(tabX + x) = (int) (x * scaleX + 0.5);

        Prt<Image> ret;
        if (IMAGE_FORMAT_RGBA_8888 == src->getFormat()) {
            ret = new Image(width, height, IMAGE_FORMAT_RGBA_8888);
            uint32_t *srcData = (uint32_t *) src->getData();
            uint32_t *retData = (uint32_t *) ret->getData();
            uint32_t *temp;
            for (int y = 0; y < height; ++y) {
                temp = srcData + (int) (y * scaleY + 0.5) * sWidth;
                for (tabX = end - width; tabX < end; ++tabX, ++retData) {
                    *retData = *(temp + *tabX);
                }
            }
        } else if (IMAGE_FORMAT_A_8 == src->getFormat()) {
            ret = new Image(width, height, IMAGE_FORMAT_A_8);
            uint8_t *srcData = (uint8_t *) src->getData();
            uint8_t *retData = (uint8_t *) ret->getData();
            uint8_t *temp;
            for (int y = 0; y < height; ++y) {
                temp = srcData + (int) (y * scaleY + 0.5) * sWidth;
                for (tabX = end - width; tabX < end; ++tabX, ++retData) {
                    *retData = *(temp + *tabX);
                }
            }
        }
        free(end - width);
        return ret;
    }

    struct _bilinear {
        int p1;
        int p2;
        uint16_t scale;
    };

    struct _abgr {
        uint8_t r;
        uint8_t g;
        uint8_t b;
        uint8_t a;
    };

    Prt<Image> EditImage::zoomImage_BilInear(Prt<Image> &src, int width, int height) {
        int sWidth = src->getWidth();
        int sHeight = src->getHeight();
        float scaleX = (float) sWidth / width;
        float scaleY = (float) sHeight / height;
        float pos;

        _bilinear *memory = (_bilinear *) malloc((width + height) * sizeof(_bilinear));
        _bilinear *tabX = memory;
        _bilinear *endX = tabX + width;

        for (int x = 0; x < width; ++x, ++tabX) {
            pos = x * scaleX;
            tabX->p1 = tabX->p2 = (int) pos;
            tabX->p2 += (0 != pos - tabX->p2);
            tabX->scale = 0xFFFF * (pos - tabX->p2);
        }
        _bilinear *tabY = memory + width;
        _bilinear *endY = tabY + height;
        for (int y = 0; y < width; ++y, ++tabY) {
            pos = y * scaleY;
            tabY->p1 = tabY->p2 = (int) pos;
            tabY->p2 += (0 != pos - tabY->p2);
            tabY->scale = 0xFFFF * (pos - tabY->p2);
        }

        Prt<Image> ret;
        if (IMAGE_FORMAT_RGBA_8888 == src->getFormat()) {
            ret = new Image(width, height, IMAGE_FORMAT_RGBA_8888);
            uint32_t *srcData = (uint32_t *) src->getData();
            _abgr *retData = (_abgr *) ret->getData();
            uint32_t *tempY1, *tempY2, c00, c01, c10, c11;

            for (tabY = endY - height; tabY < endY; ++tabY) {
                tempY1 = srcData + tabY->p1 * sWidth;
                tempY2 = srcData + tabY->p2 * sWidth;
                for (tabX = endX - height; tabX < endX; ++tabX, ++retData) {
                    c00 = *(tempY1 + tabX->p1);
                    c01 = *(tempY1 + tabX->p2);
                    c10 = *(tempY2 + tabX->p1);
                    c11 = *(tempY2 + tabX->p2);

                    retData->r = ZB(R(c00), R(c01), R(c10), R(c11), tabX->scale, tabY->scale);
                    retData->g = ZB(G(c00), G(c01), G(c10), G(c11), tabX->scale, tabY->scale);
                    retData->b = ZB(B(c00), B(c01), B(c10), B(c11), tabX->scale, tabY->scale);
                    retData->a = ZB(A(c00), A(c01), A(c10), A(c11), tabX->scale, tabY->scale);
                }
            }
        } else if (IMAGE_FORMAT_A_8 == src->getFormat()) {
            ret = new Image(width, height, IMAGE_FORMAT_A_8);
            uint8_t *srcData = (uint8_t *) src->getData();
            uint8_t *retData = (uint8_t *) ret->getData();
            uint8_t *tempY1, *tempY2, color00, color01, color10, color11;

            for (tabY = endY - height; tabY < endY; ++tabY) {
                tempY1 = srcData + tabY->p1 * sWidth;
                tempY2 = srcData + tabY->p2 * sWidth;
                for (tabX = endX - height; tabX < endX; ++tabX, ++retData) {
                    color00 = *(tempY1 + tabX->p1);
                    color01 = *(tempY1 + tabX->p2);
                    color10 = *(tempY2 + tabX->p1);
                    color11 = *(tempY2 + tabX->p2);

                    *retData = ZB(color00, color01, color10, color11, tabX->scale, tabY->scale);
                }
            }
        }
        free(memory);
        return ret;
    }


    //////////////////////////////////////////////////////////////////////////////////////////////

    Rect::Rect(int x, int y, int width, int height) :
            mX(x),
            mY(y),
            mWidth(width),
            mHeight(height) {
    }

    int Rect::getX() const {
        return mX;
    }

    void Rect::setX(int mX) {
        Rect::mX = mX;
    }

    int Rect::getY() const {
        return mY;
    }

    void Rect::setY(int mY) {
        Rect::mY = mY;
    }

    int Rect::getWidth() const {
        return mWidth;
    }

    void Rect::setWidth(int mWidth) {
        Rect::mWidth = mWidth;
    }

    int Rect::getHeight() const {
        return mHeight;
    }

    void Rect::setHeight(int mHeight) {
        Rect::mHeight = mHeight;
    }

    Rect::Rect() {}


    Rect &Rect::operator=(Rect rect) {
        mX = rect.mX;
        mY = rect.mY;
        mWidth = rect.mWidth;
        mHeight = rect.mHeight;
        return *this;
    }

    Rect::Rect(Rect *rect) {
        mX = rect->mX;
        mY = rect->mY;
        mWidth = rect->mWidth;
        mHeight = rect->mHeight;
    }


//////////////////////////////////////////////////////////////////////////////////////////////
    DrawRect::DrawRect(uint32_t sWidth, uint32_t sHeight, Rect &rect) {
        init(sWidth, sHeight, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
    }

    DrawRect::DrawRect(int sWidth, int sHeight, int dX, int dY, int dWidth, int dHeight) {
        init(sWidth, sHeight, dX, dY, dWidth, dHeight);
    }

    void DrawRect::init(int sWidth, int sHeight, int dX, int dY, int dWidth, int dHeight) {
        mSX = dX;
        mSY = dY;
        mSWidth = sWidth;
        mSHeight = sHeight;
        mDX = 0;
        mDY = 0;
        mDWidth = dWidth;
        mDHeight = dHeight;

        if (0 > mSX) {
            mDX = ~mSX + 1;
            mSX = 0;
            mDWidth = mDWidth - mDX;
        }

        if (mSX + mDWidth > sWidth)
            mDWidth = sWidth - mSX;

        if (0 > mSY) {
            mDY = ~mSY + 1;
            mSY = 0;
            mDHeight = mDHeight - mDY;
        }

        if (mSY + mDHeight > sHeight)
            mDHeight = sHeight - mSY;
    }

    int DrawRect::getSX() const {
        return mSX;
    }

    void DrawRect::setSX(int mSX) {
        DrawRect::mSX = mSX;
    }

    int DrawRect::getSY() const {
        return mSY;
    }

    void DrawRect::setSY(int mSY) {
        DrawRect::mSY = mSY;
    }

    int DrawRect::getSWidth() const {
        return mSWidth;
    }

    void DrawRect::setSWidth(int mSWidth) {
        DrawRect::mSWidth = mSWidth;
    }

    int DrawRect::getSHeight() const {
        return mSHeight;
    }

    void DrawRect::setSHeight(int mSHeight) {
        DrawRect::mSHeight = mSHeight;
    }

    int DrawRect::getDX() const {
        return mDX;
    }

    void DrawRect::setDX(int mDX) {
        DrawRect::mDX = mDX;
    }

    int DrawRect::getDY() const {
        return mDY;
    }

    void DrawRect::setDY(int mDY) {
        DrawRect::mDY = mDY;
    }

    int DrawRect::getDWidth() const {
        return mDWidth;
    }

    void DrawRect::setDWidth(int mDWidth) {
        DrawRect::mDWidth = mDWidth;
    }

    int DrawRect::getDHeight() const {
        return mDHeight;
    }

    void DrawRect::setDHeight(int mDHeight) {
        DrawRect::mDHeight = mDHeight;
    }

//////////////////////////////////////////////////////////////////////////////////////////////////

    Size::Size(int width, int height) :
            mWidth(width),
            mHeight(height) {
    }

    int Size::getWidth() const {
        return mWidth;
    }

    void Size::setWidth(int width) {
        Size::mWidth = width;
    }

    int Size::getHeight() const {
        return mHeight;
    }

    void Size::setHeight(int height) {
        Size::mHeight = height;
    }
}